package es.decoroso.communicationAgent.comunicationServer;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import es.decoroso.communicationAgent.CommunicationAgent;
import es.decoroso.communicationAgent.bean.Message;

/**
 * Creates a polled server
 * 
 * @author Daniel Klepel, Jesús Jiménez
 * @see http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html
 */
public class CommunicationServer implements Runnable {

    protected int serverPort = 9000;
    protected ServerSocket serverSocket = null;
    protected boolean isStopped = false;
    protected Thread runningThread = null;
    protected ExecutorService threadPool =
            Executors.newFixedThreadPool(10);
    private Message mensaje;
    
    private List<Runnable> threadList;

    public CommunicationServer(int port, CommunicationAgent comunicacion) {
        this.serverPort = port;
        threadList = new LinkedList<Runnable>();
    }

    public void run() {
        System.out.println("Server Started!");
        synchronized (this) {
            this.runningThread = Thread.currentThread();
        }
        openServerSocket();
        while (!isStopped()) {
            Socket clientSocket = null;
            try {
                clientSocket = this.serverSocket.accept();
            } catch (IOException e) {
                if (isStopped()) {
                    System.out.println("Server Stopped.");
                    return;
                }
                throw new RuntimeException(
                        "Error accepting client connection", e);
            }
            WorkerRunnable worker = new WorkerRunnable(clientSocket,
                    "Thread Pooled Server", this);
            threadList.add(worker);
            System.out.println("Client connected:" + clientSocket.getInetAddress().getHostName() );
            this.threadPool.execute(worker);
        }
        this.threadPool.shutdown();
        System.out.println("Server Stopped.");
    }

    private synchronized boolean isStopped() {
        return this.isStopped;
    }

    public synchronized void stop() {
        this.isStopped = true;
        try {
            this.serverSocket.close();
        } catch (IOException e) {
            throw new RuntimeException("Error closing server", e);
        }
    }

    private void openServerSocket() {
        try {
            this.serverSocket = new ServerSocket(this.serverPort);
        } catch (IOException e) {
            throw new RuntimeException("Cannot open port " + this.serverPort, e);
        }
    }

    
	public void setMessage(Message message) {
		mensaje = message;
		for (Runnable r: threadList) {
			synchronized (r) {
				r.notify();
			}
		}
	}

	public Message getMessages() {
		return mensaje;
	}

	// OBSERVER PATTERN
	public void update(Message list) {
		setMessage(list);
	}
}